package com.lzkjiot.service.gnss.transger.core.server;

import com.lzkjiot.service.gnss.transger.core.DataInFrame;
import com.lzkjiot.service.gnss.transger.core.constants.NettyConstants;
import com.lzkjiot.service.gnss.transger.core.transfer.CacheData;
import com.lzkjiot.service.gnss.transger.core.transfer.condition.ConditionCacheManager;
import com.lzkjiot.service.gnss.transger.core.transfer.gnssdata.GnssDataCacheManager;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.group.ChannelGroup;
import io.netty.channel.group.DefaultChannelGroup;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;
import io.netty.util.ReferenceCountUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

@Component
@ChannelHandler.Sharable
@Slf4j
public class GnssBusiHandler extends ChannelInboundHandlerAdapter {

    private static final ChannelGroup allIncomeChannels = new DefaultChannelGroup(null);
    private final ScheduledExecutorService channelGroupPrintWorker = Executors.newScheduledThreadPool(1);

    @Autowired
    GnssDataCacheManager gnssDataCacheManager;

    @Autowired
    ConditionCacheManager conditionCacheManager;

    @PostConstruct
    public void init() {
//        startChannelGroupPrintWorker();
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        String deviceId = ctx.channel().attr(NettyConstants.DEVICE_ID).get();
        log.info("[GNSS channel active] Device:{}, channelActive.", deviceId);
        allIncomeChannels.add(ctx.channel());
//        ctx.pipeline().addLast(new IdleStateHandler(0, 0, 60));
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) {
        DataInFrame dataInFrame = (DataInFrame) msg;
//        空数据直接丢弃
        if(dataInFrame.getGnssData().length <= 0 && dataInFrame.getConditionData().length <= 0){
            ReferenceCountUtil.release(msg);
        }
        if(dataInFrame.getConditionData().length > 0){
            conditionCacheManager.add(new CacheData(dataInFrame.getDeviceId(), dataInFrame.getConditionData()));
        }
        if(dataInFrame.getGnssData().length > 0){
            gnssDataCacheManager.add(new CacheData(dataInFrame.getDeviceId(), dataInFrame.getGnssData()));
        }
    }

    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) {
        if (evt instanceof IdleStateEvent) {
            IdleStateEvent e = (IdleStateEvent) evt;
            if (e.state() == IdleState.READER_IDLE) {
                String deviceId = ctx.channel().attr(NettyConstants.DEVICE_ID).get();
                log.error("[GNSS channel idle event] Device[{}] channel close. Cause idle timeout",deviceId);
                allIncomeChannels.remove(ctx.channel());
                ctx.close();
            }
        }
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        String deviceId = ctx.channel().attr(NettyConstants.DEVICE_ID).get();
        log.error("[GNSS] Device[{}] channel closeed. Cause exption:{}",deviceId,cause.getMessage());
        allIncomeChannels.remove(ctx.channel());
        ctx.close();
    }

    private void startChannelGroupPrintWorker() {
        channelGroupPrintWorker.scheduleAtFixedRate(() -> {
            log.info("######### GNSS tcp server income channel size:{} ", allIncomeChannels.size());
        }, 0, 30, TimeUnit.SECONDS);
    }

}
